package ar.edu.utn.frba.proyecto.grupo101;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import ar.com.siavu.controller.configuration.HibernateUtil;
import ar.com.siavu.controller.memory.AGSingleton;
import ar.com.siavu.domain.Posta;
import ar.com.siavu.domain.Usuario;

public class PoblacionInicial {

	public static List<Map<Posta, List<Usuario>>> jefes=new ArrayList<Map<Posta,List<Usuario>>>();
	public static List<Map<Posta, List<Usuario>>> comisariosInt=new ArrayList<Map<Posta,List<Usuario>>>();
	public static List<Map<Posta, List<Usuario>>> auxiliaresInt=new ArrayList<Map<Posta,List<Usuario>>>();
	
	public PoblacionInicial (){
		Session s= HibernateUtil.getSessionFactory().getCurrentSession();
		Transaction t= s.beginTransaction();
		Criteria critPosta= s.createCriteria(Posta.class);
		critPosta.createAlias("VueloIda", "vue");
		critPosta.add(Restrictions.in("vue.Numero", new Integer[]{1182,1132,1140,1160,1302,1376,1360,1364}));
		GregorianCalendar gcInicio= new GregorianCalendar();
		gcInicio.set(2010, 9-1, 1, 0, 0);
		GregorianCalendar gcFin= new GregorianCalendar();
		gcFin.set(2010, 9-1, 30, 23, 59);
		critPosta.add(Restrictions.ge("vue.FechaSalida", gcInicio.getTime()));
		critPosta.add(Restrictions.le("vue.FechaSalida", gcFin.getTime()));
		critPosta.addOrder(Order.asc("vue.FechaSalida"));
		Map<Posta, List<Usuario>> postasJefes= new LinkedHashMap<Posta, List<Usuario>>();
		Map<Posta, List<Usuario>> postasComisarios= new LinkedHashMap<Posta, List<Usuario>>();
		Map<Posta, List<Usuario>> postasAuxiliares= new LinkedHashMap<Posta, List<Usuario>>();
		List<Posta> postas= critPosta.list();
		
		Criteria critJefes= s.createCriteria(Usuario.class);
		critJefes.add(Restrictions.eq("TipoUsuario", 1));
		critJefes.add(Restrictions.eq("TipoPosta", 2));
		List<Usuario> listJefes= critJefes.list();
		
		for (int h = 0; h < postas.size(); h++) {
			postasJefes.put(postas.get(h), new ArrayList<Usuario>());
			postasComisarios.put(postas.get(h), new ArrayList<Usuario>());
			postasAuxiliares.put(postas.get(h), new ArrayList<Usuario>());
		}
		//Guardo un mapa con la programacion que estoy trabajando con el mismo formato de la preprogramacion
		Map<Usuario, String[]> programacionActual= new LinkedHashMap<Usuario, String[]>();
		Set<Usuario> usuarios=AGSingleton.getInstance().getPreprogramaciones().keySet();
		int longitudMap=AGSingleton.getInstance().getPreprogramaciones().entrySet().iterator().next().getValue().length;
		for (Usuario usuario : usuarios) {
			if (jefes.contains(usuario)){
				programacionActual.put(usuario, new String[longitudMap]);
			}
		}
		//
		for (int h = 0; h < postas.size(); h++) {
			int k= h - 1;
			
			for (int i = h; i < postas.size(); i++) {
				Posta posta= postas.get(i);
				for (int j = 0; j < posta.getVueloIda().getAvion().getCantidadJefesCabinaMinimo(); j++) {
					Usuario aux=getUsuariosforPosta(listJefes, posta, programacionActual);
					postasJefes.get(posta).add(aux);
					actualizarProgramacionActual(programacionActual,posta,aux);
				}				
			}
			
			for (int i = 0; i < h; i++) {
				Posta posta= postas.get(i);
				for (int j = 0; j < posta.getVueloIda().getAvion().getCantidadJefesCabinaMinimo(); j++) {
					Usuario aux=getUsuariosforPosta(listJefes, posta, programacionActual);
					postasJefes.get(posta).add(aux);
					actualizarProgramacionActual(programacionActual,posta,aux);
				}				
			}
			
			jefes.add(postasJefes);
		}
		
//		AGSingleton.getInstance().setJefes(new HashMap<Posta, Usuario[]>());
//		AGSingleton.getInstance().setComisarios(new HashMap<Posta, Usuario[]>());
//		AGSingleton.getInstance().setAuxiliares(new HashMap<Posta, Usuario[]>());
//		for (Posta posta : postas) {
//			AGSingleton.getInstance().getJefes().put(posta, new Usuario[posta.getVueloIda().getAvion().getCantidadJefesCabinaMaximo()]);
//			AGSingleton.getInstance().getComisarios().put(posta, new Usuario[posta.getVueloIda().getAvion().getCantidadComisariosMaximo()]);
//			AGSingleton.getInstance().getAuxiliares().put(posta, new Usuario[posta.getVueloIda().getAvion().getCantidadAuxiliaresMaximo()]);
//		}
	}
	
	private void actualizarProgramacionActual(
			Map<Usuario, String[]> programacionActual, Posta posta, Usuario aux) {
		GregorianCalendar gc= new GregorianCalendar();
		gc.setTime(posta.getVueloIda().getFechaSalida());
		int diaInicio=gc.get(GregorianCalendar.DAY_OF_MONTH);
		GregorianCalendar gcf= new GregorianCalendar();
		gcf.setTime(posta.getVueloVuelta().getFechaLlegada());
		int diaFin=gc.get(GregorianCalendar.DAY_OF_MONTH);
		
		for (int i=diaInicio -1; i<diaFin; i++){
			programacionActual.get(aux)[i]=posta.getNombre();
		}
		
	}

	private Usuario getUsuariosforPosta(List<Usuario> usuariosPuesto,Posta posta, Map<Usuario, String[]> programacionActual){
		Map<Usuario, String[]> preprogramaciones =AGSingleton.getInstance().getPreprogramaciones();
		List<Usuario> usuariosPidieronposta= getUsuariosPidieronPosta(usuariosPuesto, posta);
		List<Usuario> candidatos=new ArrayList<Usuario>();
		GregorianCalendar gc= new GregorianCalendar();
		gc.setTime(posta.getVueloIda().getFechaSalida());
		int dia=gc.get(GregorianCalendar.DAY_OF_MONTH);
		for (Usuario usuario : usuariosPidieronposta) {
			if (programacionActual.get(usuario)[dia-1]!=null){
				candidatos.add(usuario);
			}
		}
		if (candidatos.isEmpty()){
			candidatos=getUsuariosLibres(programacionActual, dia);
		}
		int pos= (int)Math.round(Math.random()*candidatos.size())%candidatos.size();
		
		return candidatos.get(pos);
	}

	private List<Usuario> getUsuariosLibres(
			Map<Usuario, String[]> programacionActual, int dia) {
		List<Usuario> usuarios= new ArrayList<Usuario>();
		for (Entry<Usuario, String[]> entry : programacionActual.entrySet()) {
			if (entry.getValue()[dia -1]== null){
				usuarios.add(entry.getKey());
			}			
		}
		return usuarios;
	}

	private List<Usuario> getUsuariosPidieronPosta(
			List<Usuario> usuariosPuesto, Posta posta) {
		GregorianCalendar gc= new GregorianCalendar();
		gc.setTime(posta.getVueloIda().getFechaSalida());
		int dia=gc.get(GregorianCalendar.DAY_OF_MONTH);
		List<Usuario> result=new ArrayList<Usuario>();
		for (Usuario usuario : usuariosPuesto) {
			String[] programacionPedida=AGSingleton.getInstance().getPreprogramaciones().get(usuario);
			if (programacionPedida[dia-1].equals(posta.getNombre())){
				if (dia>1 && (!programacionPedida[dia-2].equals(posta.getNombre()))){
					result.add(usuario);
				} else {
					//TODO: ver que hago si es el primer dia del mes.
				}

			}
		}
		return result;
	}
}
